
#ifndef LEVEL_HPP_
#define LEVEL_HPP_

#include <LinearMath\btAlignedObjectArray.h>
#include <string>
#include <vector>
#include <list>
#include <map>

class Action;
class EventManager;
class DotSceneLoader;

namespace Ogre
{
	class Node;
	class SceneNode;
	class SceneManager;
}

class btDynamicsWorld;
class btCollisionShape;
class btRigidBody;
class btGhostObject;

typedef struct
{
	std::string title;
	std::string nextlevel;
	std::string scenefile;
	double startX, startY, startZ;
} LevelInfo;

typedef struct
{
	btGhostObject* go;
	std::string postEvent;
} VolumeTriggerInfo;

typedef struct
{
	btRigidBody* rb;
	Ogre::SceneNode* node;
} KinematicObjectInfo;

/*
	This class holds the information for all levels that have been specified in the game configuration.
	It is responsible for loading/unloading levels as requested and to make sure that the scene and
	physics world is up to date for the currently chosen level.
*/
class Level
{
	public:
		Level(btDynamicsWorld* dw, Ogre::SceneManager* sm, Ogre::SceneNode* levelNode, EventManager* em) : m_pDynamicsWorld(dw), m_pSceneManager(sm), m_pLevelAttachNode(levelNode), m_currentLevel(-1), m_pEM(em) {}

		//call this to add a level to this controller
		void add(const LevelInfo& li);
		void changeLevel(std::string name);
		void nextLevel();
		void getStartPos(double& x, double& y, double& z) { x = m_Level[m_currentLevel].startX; y = m_Level[m_currentLevel].startY; z = m_Level[m_currentLevel].startZ; }

		void resetCurrentLevel();
		/*
			Call every frame to keep the level updated properly
			This will check if any volume triggers have registered collision and also update any actions that
			needs to be done on the level. Notably animations of meshes.
		*/
		void update(double dt);
		
		//call to delete all data from currently loaded level
		void cleanup(Ogre::Node* node, int depth);

		std::list<Action*>							m_Actions;
	private:
		void handleProperties(DotSceneLoader* dsl, Ogre::SceneNode* node, btRigidBody* rb);


		btDynamicsWorld*							m_pDynamicsWorld;
		Ogre::SceneManager*							m_pSceneManager;
		Ogre::SceneNode*							m_pLevelAttachNode;
		std::vector<LevelInfo>						m_Level;
		std::map<std::string, unsigned int>			m_LevelIndex;

		btAlignedObjectArray<btCollisionShape*>		m_CollisionShapes;
		btAlignedObjectArray<btRigidBody*>			m_RigidBodies;;
		std::vector<VolumeTriggerInfo>				m_VolumeTrigger;;

		int m_currentLevel;

		EventManager*								m_pEM;

		//list of all events that have registered listeners
		//we use this so we can easily find and remove listeners for specific events that have been registered
		std::vector<std::string>					m_EventList;
		std::vector<KinematicObjectInfo>			m_KinematicObjects;
};

#endif